package com.jie.server.core.entity;

import cn.hutool.crypto.symmetric.AES;
import com.jie.common.message.entity.Message;

import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.LinkedList;

/**
 * 附件
 * @author XieZhiJie
 * @date 2022/04/22 11:19
 */
public class ChannelAttachment {

    /**
     * 锁类
     */
    public static class Lock {
        public int status = 0;
    }

    /**
     * 用于表明该channel的唯一id
     */
    public int id;

    /**
     * 该锁用于锁写/阻塞队列, 以及锁status, 锁监听事件的改变
     */
    public final Lock lock = new Lock();

    /**
     * nio读写的时候要用到的ByteBuffer对象
     */
    private final ByteBuffer[] byteBufferList = new ByteBuffer[2];

    /**
     * 写信息队列
     */
    public LinkedList<Message> writeQueue = new LinkedList<>();

    /**
     * 写信息队列, 不同的是因为当前writeQueue正在被操作, 因此期间需要插入
     * 到写队列的Message先插入到这里
     */
    public LinkedList<Message> blockQueue = new LinkedList<>();

    /**
     * 会话密钥使用的AES对象
     */
    private AES aes;

    public ChannelAttachment(int byteBufferSize) {
        this.byteBufferList[0] = ByteBuffer.allocateDirect(byteBufferSize);
        this.byteBufferList[1] = ByteBuffer.allocateDirect(byteBufferSize);
    }

    /**
     * 获取nio的读ByteBuffer对象
     * @return nio的读ByteBuffer
     */
    public ByteBuffer getReadByteBuffer() {
        return this.byteBufferList[0];
    }

    /**
     * 获取nio的写ByteBuffer对象
     * @return nio的写ByteBuffer对象
     */
    public ByteBuffer getWriteByteBuffer() {
        return this.byteBufferList[1];
    }

    /**
     * 设置当前附件的用于会话加密的AES对象
     * @param aes 当前附件的用于会话加密的AES对象
     */
    public void setAes(AES aes) {
        if (this.aes == null) {
            this.aes = aes;
        }
    }

    /**
     * 获取当前附件的用于会话加密的AES对象
     * @return 当前附件的用于会话加密的AES对象
     */
    public AES getAes() {
        return this.aes;
    }

    /**
     * 利用当前attachment的锁上锁并修改key的监听事件为ops
     * @param key      key
     * @param ops      ops
     */
    public void interestOps(SelectionKey key, int ops) {
        synchronized (this.lock) {
            key.interestOps(ops);
        }
    }

}
